{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a href=\"https://bmi.readthedocs.io\"><img src=\"../../media/bmi-logo-header-text.png\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Run the `Heat` model through its BMI"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Heat` models the diffusion of temperature on a uniform rectangular plate with Dirichlet boundary conditions. This is the canonical example used in the [bmi-example-python](https://github.com/csdms/bmi-example-python) repository. View the source code for the [model](https://github.com/csdms/bmi-example-python/blob/master/heat/heat.py) and its [BMI](https://github.com/csdms/bmi-example-python/blob/master/heat/bmi_heat.py) on GitHub."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Start by importing `os`, `numpy` and the `Heat` BMI:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import numpy as np\n",
    "\n",
    "from heat import BmiHeat"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Create an instance of the model's BMI."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = BmiHeat()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What's the name of this model?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The 2D Heat Equation\n"
     ]
    }
   ],
   "source": [
    "print(x.get_component_name())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Start the `Heat` model through its BMI using a configuration file:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "# Heat model configuration\r\n",
      "shape:\r\n",
      "  - 6\r\n",
      "  - 8\r\n",
      "spacing:\r\n",
      "  - 1.0\r\n",
      "  - 1.0\r\n",
      "origin:\r\n",
      "  - 0.0\r\n",
      "  - 0.0\r\n",
      "alpha: 1.0\r\n"
     ]
    }
   ],
   "source": [
    "cat heat.yaml"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "x.initialize('heat.yaml')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Check the time information for the model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Start time: 0.0\n",
      "End time: 1.7976931348623157e+308\n",
      "Current time: 0.0\n",
      "Time step: 0.25\n",
      "Time units: s\n"
     ]
    }
   ],
   "source": [
    "print('Start time:', x.get_start_time())\n",
    "print('End time:', x.get_end_time())\n",
    "print('Current time:', x.get_current_time())\n",
    "print('Time step:', x.get_time_step())\n",
    "print('Time units:', x.get_time_units())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Show the input and output variables for the component (aside on [Standard Names](https://csdms.colorado.edu/wiki/CSDMS_Standard_Names)):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('plate_surface__temperature',)\n",
      "('plate_surface__temperature',)\n"
     ]
    }
   ],
   "source": [
    "print(x.get_input_var_names())\n",
    "print(x.get_output_var_names())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, get attributes of the grid on which the temperature variable is defined:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Grid id: 0\n",
      "Grid rank: 2\n",
      "Grid shape: (6, 8)\n",
      "Grid spacing: [1.0, 1.0]\n",
      "Grid type: uniform_rectilinear_grid\n"
     ]
    }
   ],
   "source": [
    "grid_id = x.get_var_grid('plate_surface__temperature')\n",
    "print('Grid id:', grid_id)\n",
    "print('Grid rank:', x.get_grid_rank(grid_id))\n",
    "print('Grid shape:', x.get_grid_shape(grid_id))\n",
    "print('Grid spacing:', x.get_grid_spacing(grid_id))\n",
    "print('Grid type:', x.get_grid_type(grid_id))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Through the model's BMI, zero out the initial temperature field, except for an impulse:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "temperature = np.zeros(x.get_grid_shape(grid_id))\n",
    "temperature[3, 4] = 100.0\n",
    "x.set_value('plate_surface__temperature', temperature)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Check that the temperature field has been updated:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[  0.   0.   0.   0.   0.   0.   0.   0.]\n",
      " [  0.   0.   0.   0.   0.   0.   0.   0.]\n",
      " [  0.   0.   0.   0.   0.   0.   0.   0.]\n",
      " [  0.   0.   0.   0. 100.   0.   0.   0.]\n",
      " [  0.   0.   0.   0.   0.   0.   0.   0.]\n",
      " [  0.   0.   0.   0.   0.   0.   0.   0.]]\n"
     ]
    }
   ],
   "source": [
    "initial_temperature = x.get_value('plate_surface__temperature')\n",
    "print(initial_temperature)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now advance the model by a single time step:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "x.update()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "View the new state of the temperature field:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0.   0.   0.   0.   0.   0.   0.   0. ]\n",
      " [ 0.   0.   0.   0.   0.   0.   0.   0. ]\n",
      " [ 0.   0.   0.   0.  12.5  0.   0.   0. ]\n",
      " [ 0.   0.   0.  12.5 50.  12.5  0.   0. ]\n",
      " [ 0.   0.   0.   0.  12.5  0.   0.   0. ]\n",
      " [ 0.   0.   0.   0.   0.   0.   0.   0. ]]\n"
     ]
    }
   ],
   "source": [
    "updated_temperature = x.get_value('plate_surface__temperature')\n",
    "print(updated_temperature)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There's diffusion!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Advance the model to some distant time:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "distant_time = 2.0\n",
    "while x.get_current_time() < distant_time:\n",
    "    x.update()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "View the final state of the temperature field:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[  0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0]\n",
      " [  0.0   0.2   0.9   2.1   2.8   2.1   0.9   0.0]\n",
      " [  0.0   0.7   2.2   4.7   6.2   4.7   2.1   0.0]\n",
      " [  0.0   0.9   3.0   6.1   7.9   6.1   2.8   0.0]\n",
      " [  0.0   0.6   2.0   4.1   5.3   4.1   1.8   0.0]\n",
      " [  0.0   0.0   0.0   0.0   0.0   0.0   0.0   0.0]]\n"
     ]
    }
   ],
   "source": [
    "final_temperature = x.get_value('plate_surface__temperature')\n",
    "np.set_printoptions(formatter={'float': '{: 5.1f}'.format})\n",
    "print(final_temperature)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that temperature isn't conserved on the plate:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "74.10263419151306\n"
     ]
    }
   ],
   "source": [
    "print(final_temperature.sum())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "End the model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "x.finalize()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
